// SIPStack.cpp: implementation of the CSIPStack class.
//
//////////////////////////////////////////////////////////////////////
#pragma warning(disable:4530)
#define WIN32_LEAN_AND_MEAN
#ifdef IPV6_SUPPORT
#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
#else /* linux */
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netdb.h>
#endif
	#include <stdlib.h>
	#include <stdio.h>
	#include <string.h>
#endif
#include "SIPStack.h"
#include "UDPTransport.h"
#include "InviteTransaction.h"
#include "NonInviteTransaction.h"
#include "MD5Stream.h"
#include <assert.h>
#include "Log.h"
#ifdef USE_PROXY
#include "SIPLocation.h"
#endif
#include "SIPDialog.h"

#ifndef WIN32
#include <sys/time.h>
#else
#include <windows.h>
#endif
#include <string>

using std::string;


#ifdef USE_DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

static mystring	g_strHostName;
mystring			CSIPStack::m_strSchemes[SUPPORTED_SCHEMES] = 
{
	"sip","tel","mailto","http"
};
CLock CSIPStack::m_CallIDLock;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


CSIPStack::CSIPStack()
{
#ifndef __Win32__
	unsigned long t = 0;
	struct timeval tval;
	gettimeofday(&tval, NULL);
	t = tval.tv_sec*1000 + tval.tv_usec/1000;
#else
	time_t t;
	time(&t);
#endif

	m_nTagCount = t;
	m_nBranchCount = 0;
	srand(t);
	m_nBranchStart = t;
	m_bRegistrar = false;
	m_pTUMsgFifo = NULL;
	m_nNATType = 0;
//	m_pClientVideoDialog = NULL;
}

CSIPStack::~CSIPStack()
{
	map<mystring,CTransport*>::iterator ti;
	while(!m_TransportMap.empty())
	{
		ti = m_TransportMap.begin();
		delete ti->second;
		m_TransportMap.erase(ti);		
	}
	map<mystring,CTransaction*>::iterator tt;
	while(!m_ServerTransactionMap.empty())
	{
		tt = m_ServerTransactionMap.begin();
		delete tt->second;
		m_ServerTransactionMap.erase(tt);
	}
	while(!m_ClientTransactionMap.empty())
	{
		tt = m_ClientTransactionMap.begin();
		delete tt->second;
		m_ClientTransactionMap.erase(tt);
	}
}
CSIPMessage *NewResponseMsg()
{
	return new CSIPMessage(MSG_RESPONSE);
}
CSIPMessage* CSIPStack::MakeResponse(const CSIPMessage& request, int responseCode, const char * reason)
{
   
	//DebugLog(<< "CSIPStack::makeResponse(" << request);
	CSIPMessage* response = NewResponseMsg();

	response->StatusLine().SetStatusCode(responseCode);
//	response->m_ip = request.m_ip;
//	response->m_port = request.m_port;
//	response->m_sProtocol = request.m_sProtocol;
//	response->m_connid = request.m_connid;
//	response->m_pconn = request.m_pconn;
//	response->m_Source = request.m_Source;
	response->m_Destination = request.m_Source;
	response->m_Source = request.m_Destination;
	response->SetTransactionID(request.GetTransactionID().c_str());
	
	if(request.GetTranslate())
		response->Translate() = *request.GetTranslate();
	if(request.GetFrom())
		response->From() = *request.GetFrom();
	if(request.GetTo())
		response->To() = *request.GetTo();
	if(request.GetCallId())
		response->CallId() = *request.GetCallId();
	if(request.GetCSeq())
		response->CSeq() = *request.GetCSeq();
	if(request.GetViaList()->size() > 0)
	{
		//response->GetViaList() = request.GetViaList();
		for(std::list<CSIPVia *>::const_iterator i = request.GetViaList()->begin();i!=request.GetViaList()->end();i++)
		{
			response->ViaList().push_back(new CSIPVia(**i));
		}
	}
	/*
	for(list<CSIPMessage::DestinationInfo>::const_iterator cip = request.m_DestIPList.begin();cip != request.m_DestIPList.end();cip++)
	{
		response->m_DestIPList.push_back(*cip);
	}
	*/
	// Only generate a To: tag if one doesn't exist.  Think Re-INVITE.
	// No totag for failure responses or 100s
	if (request.GetTo() && !request.GetTo()->GetValue("tag") && responseCode < 300 && responseCode > 100)
	{		
		mystring tag;
		tag += (long)rand();
		response->To().AddParam("tag",tag.c_str());
	}
	//response->setRFC2543TransactionId(request.getRFC2543TransactionId());

	//response->header(h_ContentLength).value() = 0;
   
	if (request.GetRecordRouteList()->size()>0)
	{
		COPYLIST((*request.GetRecordRouteList()),response->RecordRouteList(),CSIPRoute);
		//response->RecordRoute() = *request.GetRecordRoute();
	}

	//if (request.isExternal())
	//{
	//	response->setFromTU();
	//}
	//else
	//{
	//	response->setFromExternal();
	//}

	// added by liuhf 2007.10.24
	if(request.GetCallInfos()->size() > 0)
	{
		std::list<CSIPCallInfo *>::const_iterator iter;
		for(iter=request.GetCallInfos()->begin(); iter != request.GetCallInfos()->end(); iter++)
		{
			CSIPCallInfo * pInfo = new CSIPCallInfo;
			*pInfo = *(*(iter));
			response->CallInfos().push_front(pInfo);
		}
	}

	if(request.GetSubject())
		response->Subject() = *(request.GetSubject());


	if (reason && strlen(reason))
	{
		response->StatusLine().SetReason(reason);
	}
	else
	{
		switch (responseCode)
		{
         case 100: response->StatusLine().SetReason("Trying"); break;
         case 180: response->StatusLine().SetReason("Ringing"); break;
         case 181: response->StatusLine().SetReason("Call Is Being Forwarded"); break;
         case 182: response->StatusLine().SetReason("Queued"); break;
         case 183: response->StatusLine().SetReason("Session Progress"); break;
         case 200: response->StatusLine().SetReason("OK"); break;
         case 300: response->StatusLine().SetReason("Multiple Choices"); break;
         case 301: response->StatusLine().SetReason("Moved Permanently"); break;
         case 302: response->StatusLine().SetReason("Moved Temporarily"); break;
         case 305: response->StatusLine().SetReason("Use Proxy"); break;
         case 380: response->StatusLine().SetReason("Alternative Service"); break;
         case 400: response->StatusLine().SetReason("Bad Request"); break;
         case 401: response->StatusLine().SetReason("Unauthorized"); break;
         case 402: response->StatusLine().SetReason("Payment Required"); break;
         case 403: response->StatusLine().SetReason("Forbidden"); break;
         case 404: response->StatusLine().SetReason("Not Found"); break;
         case 405: response->StatusLine().SetReason("Method Not Allowed"); break;
         case 406: response->StatusLine().SetReason("Not Acceptable"); break;
         case 407: response->StatusLine().SetReason("Proxy Authentication Required"); break;
         case 408: response->StatusLine().SetReason("Request Timeout"); break;
         case 410: response->StatusLine().SetReason("Gone"); break;
         case 413: response->StatusLine().SetReason("Request Entity Too Large"); break;
         case 414: response->StatusLine().SetReason("Request-URI Too Long"); break;
         case 415: response->StatusLine().SetReason("Unsupported Media Type"); break;
         case 416: response->StatusLine().SetReason("Unsupported URI Scheme"); break;
         case 420: response->StatusLine().SetReason("Bad Extension"); break;
         case 421: response->StatusLine().SetReason("Extension Required"); break;
         case 423: response->StatusLine().SetReason("Interval Too Brief"); break;
         case 480: response->StatusLine().SetReason("Temporarily Unavailable"); break;
         case 481: response->StatusLine().SetReason("Call/Transaction Does Not Exist"); break;
         case 482: response->StatusLine().SetReason("Loop Detected"); break;
         case 483: response->StatusLine().SetReason("Too Many Hops"); break;
         case 484: response->StatusLine().SetReason("Address Incomplete"); break;
         case 485: response->StatusLine().SetReason("Ambiguous"); break;
         case 486: response->StatusLine().SetReason("Busy Here"); break;
         case 487: response->StatusLine().SetReason("Request Terminated"); break;
         case 488: response->StatusLine().SetReason("Not Acceptable Here"); break;
         case 491: response->StatusLine().SetReason("Request Pending"); break;
         case 493: response->StatusLine().SetReason("Undecipherable"); break;
         case 500: response->StatusLine().SetReason("Server Internal Error"); break;
         case 501: response->StatusLine().SetReason("Not Implemented"); break;
         case 502: response->StatusLine().SetReason("Bad Gateway"); break;
         case 503: response->StatusLine().SetReason("Service Unavailable"); break;
         case 504: response->StatusLine().SetReason("Server Time-out"); break;
         case 505: response->StatusLine().SetReason("Version Not Supported"); break;
         case 513: response->StatusLine().SetReason("Message Too Large"); break;
         case 600: response->StatusLine().SetReason("Busy Everywhere"); break;
         case 603: response->StatusLine().SetReason("Decline"); break;
         case 604: response->StatusLine().SetReason("Does Not Exist Anywhere"); break;
         case 606: response->StatusLine().SetReason("Not Acceptable"); break;
		}
	}
    response->m_usRequestTime = request.m_usProduceTime;
	return response;
}


/*
CSIPMessage* CSIPStack::MakeRegister(const CSIPNameAddr& registrar,
                     const CSIPNameAddr& aor,
                     const CSIPNameAddr& contact)
{
	CSIPMessage* request = new CSIPMessage();
	CSIPRequestLine rLine;
	rLine.SetMethod(REGISTER);
	rLine.Uri().SetScheme(registrar.GetUri()->GetScheme().c_str());
	rLine.Uri().SetHost(registrar.GetUri()->GetHost().c_str());
	rLine.Uri().SetPort(registrar.GetUri()->GetPort());
	
	request->To().SetNameAddr(aor);
	request->RequestLine() = rLine;
	request->MaxForwards().SetMaxForwards(70);
	CSIPSequence seq;
	seq.SetSequence(1);
	seq.SetMethod(REGISTER);
	request->CSeq() = seq;
	request->From().SetNameAddr(aor);
	request->From().AddParam("tag",CSIPStack::GetTag().c_str());
	request->CallId().SetCallId(CSIPStack::ComputeCallId().c_str());
	assert( request->GetContactList()->size() == 0);
	
	request->ContactList().push_back(new CSIPContact(contact));
	request->ViaList().push_front(new CSIPVia);
   
	return request;
}


CSIPMessage* CSIPStack::MakeSubscribe(const CSIPNameAddr& target, 
                      const CSIPNameAddr& from,
                      const CSIPNameAddr& contact)
{
	CSIPMessage* request = new CSIPMessage;
	CSIPRequestLine rLine;
	rLine.Uri() = *target.GetUri();
	rLine.SetMethod(SUBSCRIBE);
	request->To().SetNameAddr(target);
	request->RequestLine() = rLine;
	request->MaxForwards().SetMaxForwards(70);

	if (target.GetUri()->GetParams().GetValue("transport"))
	{
		rLine.Uri().Params().AddParam("transport",target.GetUri()->GetParams().GetValue("transport"));
	}
	request->CSeq().SetSequence(1);
	request->CSeq().SetMethod(SUBSCRIBE);
	request->From().SetNameAddr(from);
	request->From().AddParam("tag",CSIPStack::GetTag().c_str());

	request->CallId().SetCallId(CSIPStack::ComputeCallId().c_str());
	assert( request->GetContactList()->size() == 0);
	request->ContactList().push_front(new CSIPContact(contact));
	request->ViaList().push_front(new CSIPVia);
//	request->push_front(new CSIPVia(via));
   
	return request;
}
*/
CSIPMessage *NewRequestMsg()
{
	return new CSIPMessage(MSG_REQUEST);
}
mystring ComputeCallID(const mystring &username);
CSIPMessage* CSIPStack::MakeRequest(const CSIPNameAddr& target, const CSIPNameAddr& from, const CSIPNameAddr& contact, MethodTypes method)
{
	CSIPMessage* request = NewRequestMsg();
	CSIPRequestLine rLine;
	rLine.SetMethod(method);
	rLine.Uri() = *target.GetUri();
	request->To().SetNameAddr(target);
	request->RequestLine() = rLine;
	request->MaxForwards().SetMaxForwards(70);
	request->CSeq().SetMethod(method);
	request->CSeq().SetSequence(1);
	request->From().SetNameAddr(from);
	
	mystring tag;
	tag += (long)rand();	
	
	request->From().AddParam("tag",tag.c_str());
	request->ContactList().push_front(new CSIPContact(contact));
	request->CallId().SetCallId(ComputeCallID(from.GetUri()->AddressOfRecord()).c_str());
	request->ViaList().push_front(new CSIPVia);
	return request;
}


CSIPMessage* CSIPStack::MakeResponse(const CSIPMessage& request, int responseCode, const CSIPNameAddr& contact,  const char * reason)
{
	CSIPMessage* response = CSIPStack::MakeResponse(request, responseCode, reason);
	response->ContactList().push_front(new CSIPContact(contact));	
	return response;
}

CSIPMessage * CSIPStack::MakeACK(CSIPMessage &request,CSIPMessage &response)
{//RFC3261 17.1.1.3 Construction of the ACK Request.
//Page 129
	assert (request.GetViaList()->size() >= 1);
	assert (request.RequestLine().GetMethod() == INVITE);
   
	CSIPMessage* ack = new CSIPMessage;

	CSIPRequestLine rLine;
	rLine.SetMethod(ACK);
	rLine.Uri() = *request.RequestLine().GetUri();
	ack->RequestLine() = rLine;

	ack->CallId() = request.CallId();
	ack->From() = request.From();
	ack->To() = response.To(); // to get to-tag
	ack->ViaList().push_front(new CSIPVia(*request.ViaList().front()));
	ack->CSeq() = request.CSeq();
	ack->CSeq().SetMethod(ACK);	
	if(request.GetRouteList()->size()>0)
	{
		COPYLIST((*request.GetRouteList()),ack->RouteList(),CSIPRoute);
	}   
	//RFC3261 17.1.1.2 Formal Description Page 126
	//The ACK MUST be sent to the same address,port,and transport to whitch the original request was sent
	ack->m_Destination = request.m_Destination;//response.m_Source;
	return ack;
}

CSIPMessage* CSIPStack::MakeCancel(const CSIPMessage& request)
{
	assert(request.IsRequest());
	assert(request.GetRequestLine()->GetMethod() == INVITE);
	CSIPMessage* cancel = new CSIPMessage;

	CSIPRequestLine rLine;
	rLine.SetMethod(CANCEL);
	//rLine.SetSIPVersion(request.GetRequestLine()->GetSIPVersion().c_str());
	rLine.Uri() = *request.GetRequestLine()->GetUri();
	cancel->RequestLine() = rLine;
	cancel->To() = *request.GetTo();
	cancel->From() = *request.GetFrom();
	cancel->CallId() = *request.GetCallId();
	/*
	if (request.exists(h_ProxyAuthorizations))
	{
		cancel->header(h_ProxyAuthorizations) = request.header(h_ProxyAuthorizations);
	}
	if (request.exists(h_Authorizations))
	{
		cancel->header(h_Authorizations) = request.header(h_Authorizations);
	}
   
	if (request.exists(h_Routes))
	{
		cancel->header(h_Routes) = request.header(h_Routes);
	}
	*/
	cancel->CSeq() = *request.GetCSeq();
	cancel->CSeq().SetMethod(CANCEL);
	cancel->ViaList().push_front(new CSIPVia(*request.GetViaList()->front()));

	return cancel;
}

void CSIPStack::AddtoTUFifo(CSIPMessage *pmsg)
{
	if(m_pTUMsgFifo)
		m_pTUMsgFifo->Add(pmsg);
	else
		delete pmsg;
}

//DEL mystring CSIPStack::ComputeCallId()
//DEL {   
//DEL 	mystring cid;
//DEL 	//char buf[24];
//DEL 	timeval tv;
//DEL 	MD5Stream md5;
//DEL 	m_CallIDLock.Lock();
//DEL 	for(int i = 0;i<4;i++)
//DEL 	{
//DEL 		gettimeofday(&tv,NULL);
//DEL 		srand(tv.tv_sec%0xffff + tv.tv_usec%0x06ffffff);
//DEL 		md5 << rand();
//DEL 	}
//DEL 	m_CallIDLock.Unlock();
//DEL 	md5 << m_strUserName;
//DEL 	md5 << "@";
//DEL 	md5 << m_strHostName;
//DEL 	return md5.getHex();
//DEL }
int	CSIPStack::GetUDPPort()
{
	mystring tid;
	tid = "UDP";
	if(m_TransportMap.find(tid) == m_TransportMap.end())
		return 0;
	return m_TransportMap.find(tid)->second->GetPort();
}
int CSIPStack::GetTCPPort()
{
	mystring tid;
	tid = "TCP";
	if(m_TransportMap.find(tid) == m_TransportMap.end())
		return 0;
	return m_TransportMap.find(tid)->second->GetPort();
}

mystring CSIPStack::GetLocalAddress()
{
   // if you change this, please #def old version for windows 
	return m_strLocalAddress;
}

mystring CSIPStack::GetBranch()
{
	//int i;
	mystring str;
	str = "z9hG4bK-";
	char buf[128];
	sprintf(buf,"%ua%u%s",m_nBranchStart,m_nBranchCount++,m_strUserName.c_str());	
	
	MD5Stream md5;
	md5 << buf;
	str += md5.getHex();
	return str;
}
mystring CSIPStack::GetTag()
{
	mystring str;
	str = m_strUserName;
	char buf[32];	
	sprintf(buf,"%u",rand());
	str +=buf;
	return str;
}

int CSIPStack::TransportSendRequest(CSIPMessage &request)
{	
	CTransport *pt;
	CSIPVia *pvia= NULL;
	mystring tran;
	mystring transport;
	map<mystring,CTransport *>::iterator it;
	if(request.m_Source.type == CTransport::Unknown ||
		request.m_Source.ipv4.s_addr == 0 ||
		request.m_Source.port == 0)
	{//no proper source transport,so send the message by all transport
		for(it = m_TransportMap.begin();it != m_TransportMap.end();it++)
		{
			pt = it->second;
			assert(request.ViaList().size());
			pvia = request.GetViaList()->front();
			pvia->SetHost(pt->GetHost().c_str());
			pvia->SetPort(pt->GetPort());
			if(pt->GetType() == CTransport::TCP)
				tran = "TCP";
			else
				tran = "UDP";			
			pvia->SetTransport(tran.c_str());
		
			if(request.GetRequestLine()->GetMethod() == REGISTER && request.GetContacts().size() > 0)
			{
				request.Contacts().front()->GetNameAddr()->Uri().SetHost(pt->GetHost().c_str());
				request.Contacts().front()->GetNameAddr()->Uri().SetPort(pt->GetPort());
			}
		
			pt->SendMsg(request);
		}
	}
	else
	{
		if(request.m_Source.type == CTransport::TCP)
			tran = "TCP";
		else
			tran = "UDP";
		transport = tran;
		
		tran +=":";
		tran +=inet_ntoa(request.m_Source.ipv4);
		tran +=":";
		tran += request.m_Source.port;
		it = m_TransportMap.find(tran);
		if(it == m_TransportMap.end())
			return -1;
		
		pt = it->second;
		assert(request.ViaList().size());
		pvia = request.GetViaList()->front();
		pvia->SetHost(pt->GetHost().c_str());
		pvia->SetPort(pt->GetPort());
		pvia->SetTransport(transport.c_str());
	//	request.m_Destination.transport = pt;
	//	request.m_Destination.type = pt->GetType();
	//if(ptranid)
	//	pmsg->transactionid = ptranid;
	//pmsg->issend = TRUE;
	
		if(request.GetRequestLine()->GetMethod() == REGISTER && request.GetContacts().size() > 0)
		{
			request.Contacts().front()->GetNameAddr()->Uri().SetHost(pt->GetHost().c_str());
			request.Contacts().front()->GetNameAddr()->Uri().SetPort(pt->GetPort());
		}
#ifdef PERFORMANCE_TEST	
        timeval tv;
        gettimeofday(&tv, NULL);
        int64 beg = tv.tv_sec * 1000 * 1000  +  tv.tv_usec;
#endif
		pt->SendMsg(request);

#ifdef PERFORMANCE_TEST	
        gettimeofday(&tv, NULL);
        int64 end = tv.tv_sec * 1000 * 1000  +  tv.tv_usec;
        printf("CSIPStack::TransportSendRequest:pt->SendMsg take usec: %lld \n", end - beg);        
#endif		
	}
	return 0;
}

int CSIPStack::ProxyTransportSendRequest(CSIPMessage &request)
{
	CTransport *pt;
	CSIPVia *pvia= NULL;
	mystring tran;
	mystring transport;
	map<mystring,CTransport *>::iterator it;
	if(request.m_Source.type == CTransport::Unknown ||
		request.m_Source.ipv4.s_addr == 0 ||
		request.m_Source.port == 0)
	{//no proper source transport,so send the message by all transport
		for(it = m_TransportMap.begin();it != m_TransportMap.end();it++)
		{
			pt = it->second;
			assert(request.ViaList().size());
			pvia = request.GetViaList()->front();
			pvia->SetHost(pt->GetHost().c_str());
			pvia->SetPort(pt->GetPort());
			if(pt->GetType() == CTransport::TCP)
				tran = "TCP";
			else
				tran = "UDP";			
			pvia->SetTransport(tran.c_str());
		
			
		
			pt->SendMsg(request);
		}
	}
	else
	{
		if(request.m_Source.type == CTransport::TCP)
			tran = "TCP";
		else
			tran = "UDP";
		transport = tran;
		
		tran +=":";
		tran +=inet_ntoa(request.m_Source.ipv4);
		tran +=":";
		tran += request.m_Source.port;
		it = m_TransportMap.find(tran);
		if(it == m_TransportMap.end())
			return -1;
		
		pt = it->second;
		assert(request.ViaList().size());
		pvia = request.GetViaList()->front();
		pvia->SetHost(pt->GetHost().c_str());
		pvia->SetPort(pt->GetPort());
		pvia->SetTransport(transport.c_str());
	//	request.m_Destination.transport = pt;
	//	request.m_Destination.type = pt->GetType();
	//if(ptranid)
	//	pmsg->transactionid = ptranid;
	//pmsg->issend = TRUE;
	
	
	
		pt->SendMsg(request);
	}
	return 0;
}
int CSIPStack::TransportSendResponse(CSIPMessage &response)
{
	CTransport *pt;
	map<mystring,CTransport *>::iterator it;
	mystring tran = "UDP";
	if(response.m_Destination.type == CTransport::TCP)
		tran = "TCP";
	
	tran +=":";
	tran +=inet_ntoa(response.m_Source.ipv4);
	tran +=":";
	tran += response.m_Source.port;
	it = m_TransportMap.find(tran);
	if(it == m_TransportMap.end())
		return -1;
	
	pt = it->second;


	const char* pv;
	CSIPVia *pvia= NULL;	
	assert(response.ViaList().size());
	pvia = response.GetViaList()->front();
	if((pv = pvia->GetValue("rport")))
		response.m_Destination.port = atoi(pvia->GetValue("rport"));
	else
		response.m_Destination.port = pvia->GetPort();
	
	mystring host;
	if((pv = pvia->GetValue("received")))
	{
		host = pvia->GetValue("received");/* host store ipv6 or ipv4 address */
#ifndef IPV6_SUPPORT
		response.m_Destination.ipv4.s_addr = inet_addr(host.c_str());
#else
		response.m_Destination.ip_address = host;
#endif
	}
	else
	{
		host = pvia->GetHost(); /* host store is host */
#ifndef IPV6_SUPPORT
		response.m_Destination.ipv4.s_addr = inet_addr(host.c_str());
#else
		const char * p = host.c_str();
		response.m_Destination.ip_address.erase();
		while(*p != '\0')
		{
			if(*p == '[' || *p == ']')
				;/* note; skip [ ] */
			else
			response.m_Destination.ip_address += *p;
			p++;
		}
#endif
	}	
	response.m_Destination.transport = pt;
	response.m_Destination.type = pt->GetType();	
	pt->SendMsg(response);
	return 0;
}


bool CSIPStack::AddTransport( CTransport::TYPE protocol, 
                    int port,
                    const char* hostName)				
{
	mystring hostname = hostName;
	
	assert( !hostname.empty());
	
	mystring name;
	CTransport *ptrans = NULL;
	if(protocol == CTransport::TCP)
	{
		name = "TCP";
		
		//ptrans = new CTCPTransport(hostname.c_str(),port,nic,this);
		assert(0);
		return false;
	}
	else if(protocol == CTransport::UDP)
	{
		name = "UDP";
		ptrans = new CUDPTransport(this,hostname.c_str(),port);	
	}
	else
		return false;

	if(ptrans->IsOK() == false)
	{
		delete ptrans;
		Loger.printf(LOG_ERROR,"[CSIPStack::AddTransport] create udptransport error");
		return false;
	}
	name +=":";
	name +=hostname;
	name +=":";
	name += ptrans->GetPort();

//	m_strLocalAddress = hostname;
	m_TransportMap.insert(pair<mystring,CTransport*>(name,ptrans));
	//m_TransportMap[name] = ptrans;
	Loger.printf(LOG_DEBUG,"[CSIPStack::AddTransport] size=%d name=%s this=%X!",
				m_TransportMap.size(),name.c_str(),this);

	return true;
}

int CSIPStack::ProcessTransport()
{  
//RFC3261 18. Transport
	int ret = 0;
	CSIPMessage *pmsg=NULL;	
#ifdef MULTI_THREAD
#else
	map<mystring, CTransport*>::iterator it;
	for(it = m_TransportMap.begin();it != m_TransportMap.end();it++)
#endif
	{
#ifdef MULTI_THREAD
#ifdef PERFORMANCE_TEST	
        timeval tv;
        gettimeofday(&tv, NULL);
        int64 beg = tv.tv_sec * 1000 * 1000  +  tv.tv_usec;
        int test = m_TransportMsgFifo.Size();
        printf("Time now(second) %d, CSIPStack::ProcessTransport m_TransportMsgFifo SIZE = %d \n", tv.tv_sec,  test);

        static int SIPMsgCnt = 0;
        ++SIPMsgCnt;
        
        static uint64 statistic_last = tv.tv_sec * 1000 * 1000 + tv.tv_usec;
        uint64  statistic_seg = (tv.tv_sec * 1000 * 1000 + tv.tv_usec) - statistic_last;
        if(statistic_seg > 500*1000)
        {
            printf("SIP Message Process speed (number per sec) %lld \n", (SIPMsgCnt * 1000 * 1000)/statistic_seg);   
            SIPMsgCnt = 0;
            statistic_last = tv.tv_sec * 1000 * 1000 + tv.tv_usec;
        }
            
        
#endif        
        pmsg = m_TransportMsgFifo.GetNext();
	  	if(m_TransportMsgFifo.Size() > 500)
	  	{
        		Loger.printf(LOG_ERROR, "CSIPStack::ProcessTransport m_TransportMsgFifo SIZE = %d ", m_TransportMsgFifo.Size());
	  	}
#else
		
		  pmsg = it->second->RecvMsg();
		
#endif	
		if(pmsg!=NULL)
		{
			ret = 1;
			if(pmsg->IsRequest())
			{//RFC3261 18.2.1 PAGE145
				CSIPVia *pvia=NULL;		
				in_addr ina;
				char port[32];
				map<mystring,CTransaction*>::iterator pitem;
				mystring tid;
				mystring branch;
				//examine the value of the "sent-by" parameter in the top via
#ifdef SIP_P2P
                //The response will send to the original sender directly, not via sip proxy
                while(pmsg->ViaList().size() > 1)
                {   
                    pvia = pmsg->ViaList().front();
            		delete pvia;	
                    pmsg->ViaList().pop_front();
                }
	    	    pvia = pmsg->ViaList().back();
                if(pvia != NULL)
            	{
            	    pmsg->m_Source.ipv4.s_addr = inet_addr(pvia->GetHost().c_str());
        		    pmsg->m_Source.port = pvia->GetPort();
        		}
#else				
				pvia = pmsg->ViaList().front();				
    #ifndef IPV6_SUPPORT
				ina.s_addr = inet_addr(pvia->GetHost().c_str());
				if(ina.s_addr != pmsg->m_Source.ipv4.s_addr)
				{
					pvia->AddParam("received",inet_ntoa(pmsg->m_Source.ipv4));	
					sprintf(port,"%d",pmsg->m_Source.port);
					pvia->AddParam("rport",port);
					if(pmsg->GetRequestLine()->GetMethod() == REGISTER)
					{
						pmsg->Translate().AddNameAddr(*pmsg->Contacts().front()->GetNameAddr());
					}
				}
    #else
				/*222 */

				if(pvia->GetHost() != pmsg->m_Source.ip_address)
				{
					mystring tmphost;
					tmphost = "[";
					tmphost += pmsg->m_Source.ip_address;
					tmphost +="]";	
					if(pvia->GetHost() != tmphost)
					{
						pvia->AddParam("received",pmsg->m_Source.ip_address.c_str());		
						if(pmsg->GetRequestLine()->GetMethod() == REGISTER)
						{
							pmsg->Translate().AddNameAddr(*pmsg->Contacts().front()->GetNameAddr());
						}
					}
				}
    #endif

       
				//check for behind NAT
				if(pvia && pvia->GetValue("rport"))
				{//the endpoint is behind NAT			
					sprintf(port,"%d",pmsg->m_Source.port);
					pvia->SetValue("rport",port);
    #ifndef IPV6_SUPPORT
					if(pvia->GetValue("received"))
						pvia->SetValue("received",inet_ntoa(pmsg->m_Source.ipv4));
					else
						pvia->AddParam("received",inet_ntoa(pmsg->m_Source.ipv4));
    #else
					if(pvia->GetValue("received"))
						pvia->SetValue("received",pmsg->m_Source.ip_address.c_str());
					else
						pvia->AddParam("received",pmsg->m_Source.ip_address.c_str());
    #endif
				}
				else if(pvia->GetPort() != pmsg->m_Source.port)
				{
					//pvia->AddParam("received",inet_ntoa(pmsg->m_Source.ipv4));
				//	sprintf(port,"%d",pmsg->m_Source.port);
				//	pvia->SetValue("rport",port);
				}
#endif //SIP_P2P				
				
				//PAGE146
				//next, the server transport attempts to match the request to a server transaction.
				//using the matching rules described in Section 17.2.3
				//match the request to a server tansaction. using the matching rules described in Section 17.2.3
				//transaction id = branch + sent-by + method
				branch = pvia->GetBranch();
				if(branch.empty())
				{
					timeval tv;
					gettimeofday(&tv,0);
					char buf[128];
					sprintf(buf,"z9hG4bK%u%u",tv.tv_sec*1000000,tv.tv_usec);
					branch = buf;
					pvia->AddBranch(buf);
				}

                
				if(branch.empty() || strncmp(branch.c_str(),"z9hG4bK",7))
				{//slient descard it
					delete pmsg;
#ifndef MULTI_THREAD
					continue;
#else
					return ret;
#endif
				}
				tid = branch;
				tid += "-";
				tid += pvia->GetHost();
				tid += ":";
				sprintf(port,"%d",pvia->GetPort());
				tid += port;
				tid += "-";
				//for cancel is a transaction
				if(pmsg->GetRequestLine()->GetMethod() == ACK)
					tid += "INVITE";
				else
					tid += GetMethodName(pmsg->GetRequestLine()->GetMethod());
				//Loger.printf(LOG_MSG,"Transport:%s",pmsg->Encoding().c_str());
			//	TRACE("find: %s\r\n",tid.c_str());
				//rfc326117.2.3 Page141 \
				//Because the matching rules include the Request-URI, the server cannot match a respnse to a transaction.
				//When the TU passes a response to the server transaction, it must pass it to the specific server transaction
				//for which the response is trageted.
				pmsg->SetTransactionID(tid.c_str());
				//find server-transaction
                m_ServerTransactionMapLocker.Lock();    
                pitem = m_ServerTransactionMap.find(tid);
				if(pitem == m_ServerTransactionMap.end())
				{//not find a matching transaction, pass to the core
				 //core process, create a new transaction				
					m_CoreMsgFifo.Add(pmsg);
				}
				else
				{
					//add by sunth begin RFC3261:18.2.1
					if(pitem->second->IsTerminated()
							&& pmsg->GetRequestLine()->GetMethod() == ACK)
					{
						m_CoreMsgFifo.Add(pmsg);
					}//end
					else
					{
						pitem->second->AddRecvMessage(pmsg);
					}

				}
                m_ServerTransactionMapLocker.Unlock();
			}
			else
			{//18.1.2 receiving responses
				CSIPVia *pvia;
				if(pmsg->ViaList().size() <= 0)
				{//error,silently discarded.
					delete pmsg;
#ifndef MULTI_THREAD
					continue;
#else
					return ret;
#endif
				}
				//17.1.3 Matching Responses to Client Transactions. Page 132
				//1. match branch parameter
				//2. match method for CANCEL request constitutes a different transaction.
				pvia = pmsg->GetViaList()->front();
				//match the response to a client tansaction. using the matching rules described in Section 17.1.3
				//+method is needed since a CANCEL request constitutes a different transaction
				//transaction id = branch + sent-by + method
				mystring tid;
				tid = pvia->GetBranch();
				tid +="-";
				tid += GetMethodName(pmsg->GetCSeq()->GetMethod());
				
				//find client-transaction
				m_ClientTransactionMapLocker.Lock();
				map<mystring,CTransaction*>::iterator pitem = m_ClientTransactionMap.find(tid);
				if(pitem == m_ClientTransactionMap.end())
				{//not find a matching transaction, pass to the core
				 //core process, descase it or forward the message.
				 // as a stateless proxy, just forward the message.					
                    //Loger.printf(LOG_ERROR,"[CSIPStack::ProcessTransport] NotFound size=%d tid=%s this=%X!",
				    //m_ClientTransactionMap.size(),tid.c_str(),this);
					m_CoreMsgFifo.Add(pmsg);
#ifndef MULTI_THREAD
                    m_ClientTransactionMapLocker.Unlock();
					continue;
#else
                    m_ClientTransactionMapLocker.Unlock();
					return ret;
#endif
				}
                //Loger.printf(LOG_ERROR,"[CSIPStack::ProcessTransport] Found size=%d tid=%s this=%X!",
				//m_ClientTransactionMap.size(),tid.c_str(),this);
				pitem->second->AddRecvMessage(pmsg);
                m_ClientTransactionMapLocker.Unlock();
			}
		}
/*		else
		{
       	 	Loger.printf(LOG_WARNING, "CSIPStack::ProcessTransport m_TransportMsgFifo pmsg== NULL.");
		}
*/	}

	return ret;
}
int CSIPStack::RequestValidation(const CSIPMessage *pmsg)
{//RFC3261 16.3 Request Validation, Page94
	//1.Reasonable syntax check
	if(pmsg->GetViaList()->size() <= 0)
		return 400;
	if(pmsg->GetTo() == NULL)
		return 400;
	if(pmsg->GetFrom() == NULL)
		return 400;
	if(pmsg->GetCallId() == NULL)
		return 400;
	if(pmsg->GetCSeq() == NULL)
		return 400;
	if(pmsg->GetRequestLine() == NULL )//|| pmsg->GetRequestLine()->GetSIPURI() == NULL)
		return 400;
	//2.URI scheme check
	if(IsSupportedScheme(pmsg->GetRequestLine()->GetUri()->GetScheme()) == false)
		return 416;//Unsupported URI scheme.
	//3.Max-Forwards check
	if(pmsg->GetMaxForwards() && pmsg->GetMaxForwards()->GetMaxForwards() == 0)
	{
		if(pmsg->GetRequestLine()->GetMethod() == OPTIONS)
			return 200;//as the final recipient and respond per Secton 11. 					
		return 483;//Too many hops.
	}
	//4.Optional Loop Detection check	
	mystring branch;
	for(list<CSIPVia *>::const_iterator i = pmsg->GetViaList()->begin(); i!= pmsg->GetViaList()->end();i++)
	{
		if(stricmp(pmsg->m_Source.transport->GetHost().c_str(),(*i)->GetHost().c_str()) == 0 &&
			pmsg->m_Source.transport->GetPort() == (*i)->GetPort())
		{
			branch = "z9hG4bK-" + ComputeBranch(pmsg);
			if(branch == (*i)->GetBranch())
			{
				return 482;//Loop Detected
			}
		}
	}
	//5.Poxy-Require check
#ifdef PC_CLIENT
	for(list<CSIPProxyRequire *>::const_iterator pi = pmsg->GetProxyRequireList()->begin();pi != pmsg->GetProxyRequireList()->end();pi++)
	{
		//if((*pi)->GetOptionTag() == 
	}
#endif
	//6.Proxy-Authorization check
	//...
	return 0;
}
//Add a server side transaction
void CSIPStack::AddTransaction(CSIPMessage *pmsg)
{
//match the request to a server tansaction. using the matching rules described in Section 17.2.3
//transaction id = branch + sent-by + method
	mystring tid;
	CSIPVia *pvia = pmsg->ViaList().front();
	mystring branch = pvia->GetBranch();
	if(branch.empty() == false)
	{
		char port[32];
		tid = branch;
		tid += "-";
		tid += pvia->GetHost();
		tid += ":";
		sprintf(port,"%d",pvia->GetPort());
		tid += port;
		tid += "-";		
		tid += GetMethodName(pmsg->GetRequestLine()->GetMethod());
	}
	else
	{//backword campatibility with RFC2543
		//for INVITE request
		//tid = Requist-RUI + To tag + From tag + Call-ID + CSeq + topVia header field
		
		//for non-INVITE request
		//tid = Requist-RUI + To tag + From tag + Call-ID + CSeq + Method + topVia header field
	//	tid = "z9hG4bK-" + GetRFC2543TransactionID(pmsg);
	}
	pmsg->SetTransactionID(tid.c_str());
	
	//core process, create a new transaction
	CTransaction *pt;
	if(pmsg->GetRequestLine()->GetMethod() != INVITE)
	{//create non-INVITATE Transaction
		pt = new CNonInviteTransaction(tid.c_str(),this,FALSE);
//		Loger.printf(LOG_MSG,"Add noninvitetransaction");
	}
	else
	{//create INVITE Transaction
		pt = new CInviteTransaction(tid.c_str(),this,FALSE);
//		Loger.printf(LOG_MSG,"Add invitetransaction");
	}

	
	pt->m_nCSeq = pmsg->GetCSeq()->GetCSeq();
	pt->m_strCallID = pmsg->GetCallId()->GetCallId();
	if(pmsg->GetFrom()->GetValue("tag"))
		pt->m_strFromTag = pmsg->GetFrom()->GetValue("tag");
	if(pmsg->GetTo()->GetValue("tag"))
		pt->m_strToTag = pmsg->GetTo()->GetValue("tag");
	m_ServerTransactionMapLocker.Lock();//yb add 20100118, multi_thread ready
    assert(m_ServerTransactionMap.find(tid) == m_ServerTransactionMap.end());
    m_ServerTransactionMap.insert(pair<mystring,CTransaction*>(tid,pt));
	pt->AddRequestMessage(pmsg);
    m_ServerTransactionMapLocker.Unlock();//yb add 20100118, multi_thread ready
}

mystring CSIPStack::ComputeBranch(const CSIPMessage *pmsg)
{//RFC3261 16.6  8.Add a Via header filed value
	MD5Stream strm;	

//	modify by sunth, RFC3261:8.1.1.7 ACK'branch id must same as invite's branch id!
//	if(pmsg->GetTo()->GetValue("tag"))
//	if(pmsg->GetTo()->GetValue("tag") && pmsg->GetMethod() != ACK)
//		strm << pmsg->GetTo()->GetValue("tag");

    if (pmsg->GetMethod() != INVITE &&
    	pmsg->GetMethod() != ACK &&
    	pmsg->GetMethod() != CANCEL &&
    	pmsg->GetTo()->GetValue("tag"))
    {
    	strm << pmsg->GetTo()->GetValue("tag");
    }
	
	if(pmsg->GetFrom()->GetValue("tag"))
		strm << pmsg->GetFrom()->GetValue("tag");

	strm << pmsg->GetCallId()->GetCallId();
		
	strm << pmsg->GetRequestLine()->GetUri()->GetScheme();
	strm << pmsg->GetRequestLine()->GetUri()->GetUser();
	strm << pmsg->GetRequestLine()->GetUri()->GetHost();
	strm << pmsg->GetRequestLine()->GetUri()->GetPort();
	strm << pmsg->GetRequestLine()->GetUri()->GetPassword();

	strm << pmsg->GetViaList()->front()->GetProtocolName();
	strm << pmsg->GetViaList()->front()->GetProtocolVersion();
	strm << pmsg->GetViaList()->front()->GetTransport();
	strm << pmsg->GetViaList()->front()->GetHost();
	strm << pmsg->GetViaList()->front()->GetPort();
	strm << pmsg->GetCSeq()->GetCSeq();
	return strm.getHex();
}
bool CSIPStack::IsSupportedScheme(const mystring &scheme)
{	
	int i;
	for(i=0;i<SUPPORTED_SCHEMES;i++)
	{
		if(scheme == m_strSchemes[i])
		{
			break;
		}
	}
	if(i >= SUPPORTED_SCHEMES)
	{//Unsupported URI Scheme. response 416
		return false;
	}
	return true;
}

void CSIPStack::SendRequest(CSIPMessage &umsg)
{	
//add by owen, fix the bug,witch cause via header's branch params growing too many.
//2006/9/20
#ifdef PERFORMANCE_TEST	
    timeval tv;
    gettimeofday(&tv, NULL);
    int64 beg = tv.tv_sec * 1000 * 1000  +  tv.tv_usec;
#endif
    CSIPMessage msg;
	msg = umsg;
//end add.
	CTransaction *pt;
	CSIPVia *pvia;
	if(msg.ViaList().size() == 0)
	{
		pvia = new CSIPVia;
		msg.ViaList().push_front(pvia);
	}
	else
		pvia = msg.ViaList().front();
	pvia->AddBranch(GetBranch().c_str());
		
	mystring tid = pvia->GetBranch();
//	Loger.printf(LOG_MSG,"%s",tid.c_str());
	tid += "-";
	tid += GetMethodName(msg.GetRequestLine()->GetMethod());
	
	if(msg.GetRequestLine()->GetMethod() != INVITE)
	{
		pt = new CNonInviteTransaction(tid.c_str(),this,TRUE);
	}
	else
	{
		pt = new CInviteTransaction(tid.c_str(),this,TRUE);
	}
	
	pt->m_nCSeq = msg.GetCSeq()->GetCSeq();
	pt->m_strCallID = msg.GetCallId()->GetCallId();
	if(msg.GetFrom()->GetValue("tag"))
		pt->m_strFromTag = msg.GetFrom()->GetValue("tag");
	if(msg.GetTo()->GetValue("tag"))
		pt->m_strToTag = msg.GetTo()->GetValue("tag");
	
	if(m_nNATType > 0)
	{
		if(!pvia->FindParam("rport"))
			pvia->AddParam("rport","");
	}

    pt->SendRequest(msg);
   
	m_ClientTransactionMapLocker.Lock();
	m_ClientTransactionMap.insert(pair<mystring,CTransaction*>(tid, pt));
	m_ClientTransactionMapLocker.Unlock();
#ifdef PERFORMANCE_TEST	
    gettimeofday(&tv, NULL);
    int64 end = tv.tv_sec * 1000 * 1000  +  tv.tv_usec;
    printf("CSIPStack::SendRequest: take usec: %lld \n", end - beg);
#endif 
   
}

int CSIPStack::ProcessTransaction()
{
	int ret = 0;
	map<mystring,CTransaction*>::iterator it,delit;
#ifdef PERFORMANCE_TEST
	//printf("Before ProcessTransaction  m_ClientTransactionMap size = %d \n", m_ClientTransactionMap.size());
#endif
	for(it = m_ClientTransactionMap.begin();it != m_ClientTransactionMap.end();)
	{	
	    //::usleep(10);
		it->second->Process();
      #ifdef MULTI_THREAD
        if(it->second->m_bNeedBySendProc == false && it->second->IsTerminated())
      #else
        if(it->second->IsTerminated())
      #endif		
		{	           
    		m_ClientTransactionMapLocker.Lock();//yb added
    		Loger.printf(LOG_MSG, "Client Transaction terminated: %s", it->first.c_str());
			delit = it;
			it++;
			delete delit->second;
			delit->second = NULL;
			m_ClientTransactionMap.erase(delit);
            m_ClientTransactionMapLocker.Unlock();//yb added
		}
		else
			it++;
	}
#ifdef PERFORMANCE_TEST		
    //printf("After ProcessTransaction  m_ClientTransactionMap size = %d \n", m_ClientTransactionMap.size());
    //printf("Before ProcessTransaction  m_ServerTransactionMap size = %d \n", m_ServerTransactionMap.size());
#endif
	for(it = m_ServerTransactionMap.begin();it != m_ServerTransactionMap.end();)
	{
	    //::usleep(10);
		it->second->Process();
	  #ifdef MULTI_THREAD
        if(it->second->m_bNeedBySendProc == false && it->second->IsTerminated())
      #else
        if(it->second->IsTerminated())
      #endif	
		{
    		m_ServerTransactionMapLocker.Lock();//yb added 20100118 
    		Loger.printf(LOG_MSG, "Server Transaction terminated: %s", it->first.c_str());
			delit = it;
			it++;
			delete delit->second;
			m_ServerTransactionMap.erase(delit);
         	m_ServerTransactionMapLocker.Unlock();//yb added 20100118 
		}
		else
			it++;
	}
#ifdef PERFORMANCE_TEST	
    //printf("After ProcessTransaction  m_ServerTransactionMap size = %d \n", m_ServerTransactionMap.size());   
#endif
	return ret;
}

bool CSIPStack::SendResponse(CSIPMessage &msg)
{
    m_ServerTransactionMapLocker.Lock();//yb add 20100118 multi_thread ready
	map<mystring,CTransaction*>::iterator it = m_ServerTransactionMap.find(msg.GetTransactionID());
	if(it != m_ServerTransactionMap.end())
	{
		CTransaction *pt = it->second;
		it->second->SendResponse(msg);
        m_ServerTransactionMapLocker.Unlock();//yb add 20100118 multi_thread ready
		return true;
	}
    m_ServerTransactionMapLocker.Unlock();//yb add 20100118 multi_thread ready
	return false;
}

bool CSIPStack::UDPNATExpiresSend(mystring & ip_address, uint16 port)
{
	return true;
	mystring tran = "UDP";	
	CTransport *pt = m_TransportMap.find(tran)->second;
	if(pt)
	{
		char buf[2];
		CUDPTransport *ut = (CUDPTransport *)pt;
#ifdef IPV6_SUPPORT
                if(ut->Sendbuf(ip_address, port, buf,0) == -1)
	        	return false;
#else
		sockaddr_in addr;
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.s_addr = inet_addr(ip_address.c_str());
		if(ut->Send(addr,buf,0) == -1)
			return false;
#endif
		return true;
	}
	else
		return false;
}

void CSIPStack::SetHostName(const char *phostname)
{
	m_strHostName = phostname;
	g_strHostName = phostname;
}
mystring ComputeCallID(const mystring &username)
{ 
	static unsigned long callid = 0;
	static unsigned long callidcount = 0;
	timeval tv;
	MD5Stream md5;	
	if(callid == 0)
	{
		gettimeofday(&tv,NULL);
		callid = tv.tv_sec*1000000 + tv.tv_usec;
	}
	mystring cid;
	char buf[32];
	CSIPStack::m_CallIDLock.Lock();
	sprintf(buf,"%10u%08u",callid,callidcount++);
	md5 << buf;
	md5 << username;
	md5 << "@";
	md5 << g_strHostName;
	CSIPStack::m_CallIDLock.Unlock();
	return md5.getHex();
}
